package com.hospital.registrationappointment.module.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.api.EcardService;
import com.hospital.common.core.exception.ExceptionHelp;
import com.hospital.common.core.exception.ExceptionHelpEnum;
import com.hospital.common.core.module.controller.vo.CancelReq;
import com.hospital.common.core.module.controller.vo.ReservationReq;
import com.hospital.common.core.module.entity.PatientInfo;
import com.hospital.common.core.result.SuccessTip;
import com.hospital.common.core.result.Tip;
import com.hospital.common.core.utils.DateUtil;
import com.hospital.registrationappointment.module.entity.*;
import com.hospital.registrationappointment.module.mapper.ClinicAppointsMapper;
import com.hospital.registrationappointment.module.mapper.ClinicForRegistMapper;
import com.hospital.registrationappointment.module.mapper.ClinicSequenMapper;
import com.hospital.registrationappointment.module.service.ClinicSequenService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lvyao
 * @since 2023-10-17
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ClinicSequenServiceImpl extends ServiceImpl<ClinicSequenMapper, ClinicSequen> implements ClinicSequenService {
    @Resource
    private ClinicSequenMapper clinicSequenMapper;
    @Resource
    private ClinicForRegistMapper clinicForRegistMapper;

    @Resource
    private ClinicAppointsMapper clinicAppointsMapper;

    @Resource
    private EcardService ecardService;

    @Override
    public Tip insertReservation(ReservationReq reservationReq) {

        Tip tip = new SuccessTip();
        ClinicIndex clinicIndex = clinicSequenMapper.getbyClinicLable(reservationReq.getClinicLabel());
        if (ObjectUtil.isNull(clinicIndex)) {
            return new SuccessTip(ExceptionHelpEnum.REGIST_QUERY_CONFIG);
        }
        reservationReq.setDeptCode(clinicIndex.getClinicDept());
        reservationReq.setClinicType(clinicIndex.getClinicType());
        //1.需判断该患者在此时间段是否有过预约记录，如有预约记录则提示同一个科室 同一个医生只能预约一次。
        int count = clinicSequenMapper.getcountTimes(reservationReq.getPatientId(), reservationReq.getVisitTime(), reservationReq.getClinicLabel(),
                reservationReq.getDeptCode() == null ? reservationReq.getDeptName() : reservationReq.getDeptCode(), reservationReq.getTimeQuantum());
        if (count == 0) {
            //2.需判断该医生的该时间段号源是否已被预约完，如已预约完则提示该时间段号源已预约完，请选择其他号源
            List<ClinicForRegist> clinicForRegists = getForRegist(reservationReq.getVisitTime(), reservationReq.getClinicLabel()
                    , reservationReq.getTimeDesc(), reservationReq.getTimeQuantum());
            ClinicForRegist clinicForRegist;
            if (CollectionUtils.isNotEmpty(clinicForRegists)) {
                clinicForRegist = clinicForRegists.get(0);
                Integer registrationLimits = clinicForRegist.getRegistrationLimits();
                Integer appointmentLimits = clinicForRegist.getAppointmentLimits();
                Integer appointmentNum = clinicForRegist.getAppointmentNum();
                if (ObjectUtil.isNotNull(appointmentLimits)) {
                    if (ObjectUtil.isNotNull(appointmentNum) && appointmentNum.equals(appointmentLimits)) {
                        return new SuccessTip(ExceptionHelpEnum.REGIST_NONE);
                    }
                } else {
                    if (ObjectUtil.isNotNull(registrationLimits)) {
                        if (ObjectUtil.isNotNull(appointmentNum) && appointmentNum.equals(registrationLimits)) {
                            return new SuccessTip(ExceptionHelpEnum.REGIST_NONE);
                        }
                    }
                }
                Integer registrationNum = clinicForRegist.getRegistrationNum();

                //3.查看该患者是否有爽约记录，爽约超过5次则提示：您已经爽约超过5次!如需挂号,请您在窗口办理!
                List<ClinicAppoints> clinicAppointsList = getClinicAppoints(reservationReq.getPatientId(), reservationReq.getClinicLabel());
                if (CollectionUtils.isNotEmpty(clinicAppointsList) && clinicAppointsList.size() >= 5) {
                    return new SuccessTip(ExceptionHelpEnum.REGIST_REFUSE);
                }
                //4.clinic_appoint表插入数据
                PatientInfo patientInfo = ecardService.getPatientInfo(reservationReq.getPatientId());
                PatMasterIndex patMasterIndex = new PatMasterIndex();
                BeanUtils.copyProperties(patientInfo,patMasterIndex);
                ClinicAppoints clinicAppoints = new ClinicAppoints();
                String appointId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
                clinicAppoints.setAppointId(appointId);
                clinicAppoints.setAppointCusid(reservationReq.getPatientId());
                clinicAppoints.setCusId(reservationReq.getPatientId());
                clinicAppoints.setVisitTime(DateUtil.parse(reservationReq.getVisitTime(), "yyyy-MM-dd"));
                clinicAppoints.setAppointTime(DateUtil.format(DateUtil.parseTime(reservationReq.getReqDate())));
                clinicAppoints.setCreateTime(DateUtil.format(clinicSequenMapper.getSysdate()));
                clinicAppoints.setHospitalCode(reservationReq.getHospitalCode());
                clinicAppoints.setHospitalName(reservationReq.getHospitalName());
                clinicAppoints.setDeptCode(reservationReq.getDeptCode());
                clinicAppoints.setDeptName(clinicSequenMapper.getDeptName(reservationReq.getDeptCode()));
                clinicAppoints.setOutpOrInp("0");
                clinicAppoints.setAppointType(reservationReq.getAppointType());
                clinicAppoints.setAppointStatus("0");
                clinicAppoints.setDoctorId(reservationReq.getDoctorCode());
                clinicAppoints.setDoctorName(clinicSequenMapper.getDoctorName(reservationReq.getDoctorCode()));
                clinicAppoints.setDoctorStaffNo(reservationReq.getDoctorCode());
                clinicAppoints.setClinicLabel(reservationReq.getClinicLabel());
                clinicAppoints.setTimeDesc(reservationReq.getTimeDesc());
                clinicAppoints.setTimeQuantum(reservationReq.getTimeQuantum());
                clinicAppoints.setAppointNo(clinicSequenMapper.getAppointNo());
                clinicAppoints.setName(patMasterIndex.getName());
                clinicAppoints.setClinicType(reservationReq.getClinicType());

                //5.clinic_sequen表插入数据
                ClinicSequen clinicSequen = new ClinicSequen();
                String visitNoNext = clinicSequenMapper.getVisitNoNext();
                clinicSequen.setVisitNo(reservationReq.getVisitTime().replace("-", "") + visitNoNext);
                clinicSequen.setCardNo(patMasterIndex.getRundcode() == null ? "" : reservationReq.getPatientId() + "==" + patMasterIndex.getRundcode());
                clinicSequen.setPatientId(reservationReq.getPatientId());
                clinicSequen.setSex(patMasterIndex.getSex());
                clinicSequen.setAge(String.valueOf(DateUtil.getAge(patMasterIndex.getDateOfBirth())));
                clinicSequen.setName(patMasterIndex.getName());
                String clinicDept = clinicSequenMapper.getClinicDept(reservationReq.getDeptCode());
                if (StringUtils.isBlank(clinicDept)) {
                    return new SuccessTip(ExceptionHelpEnum.REGIST_CLINIC_CONFIG);
                }
                clinicSequen.setDeptCode(clinicDept);
                clinicSequen.setSequenCode("-");
                clinicSequen.setSequenClass("P");
                clinicSequen.setSequenNo(-1);
                String[] split = reservationReq.getTimeQuantum().split("-");
                String time = split[0] + ":01";
                clinicSequen.setEnterTime(DateUtil.format(DateUtil.parseTime(reservationReq.getVisitTime() + " " + time)));
                clinicSequen.setIsAppoint("1");
                clinicSequen.setAppointId(appointId);

                try {
                    Integer insertClinicAppoints = clinicAppointsMapper.insert(clinicAppoints);
                } catch (Exception e) {
                    throw new ExceptionHelp(ExceptionHelpEnum.REGIST_APPOINTS_INSERT);
                }
                try {
                    Integer insertClinicSequen = clinicSequenMapper.insert(clinicSequen);
                } catch (Exception e) {
                    throw new ExceptionHelp(ExceptionHelpEnum.REGIST_CLINIC_SEQUEEN);
                }
                //6.更新排班表号源数据
                clinicForRegist.setAppointmentNum(clinicForRegist.getAppointmentNum() + 1);
                try {
                    Integer update = clinicForRegistMapper.update(clinicForRegist, getlinicForRegistQueryWrapper(reservationReq.getVisitTime(), reservationReq.getClinicLabel()
                            , reservationReq.getTimeDesc(), reservationReq.getTimeQuantum()));
                } catch (Exception e) {
                    throw new ExceptionHelp(ExceptionHelpEnum.REGIST_CLINIC_FOR_REGIST);
                }
                tip.setData(clinicAppoints);
            } else {
                tip = new SuccessTip(ExceptionHelpEnum.REGIST_NULL);
            }
        } else {
            tip = new SuccessTip(ExceptionHelpEnum.REGIST_MORE);
        }
        return tip;
    }

    @Override
    public Tip cancelRegister(CancelReq cancelReq) {
        Tip tip = new SuccessTip();
        ClinicAppoints clinicAppoints = clinicAppointsMapper.selectById(cancelReq.getAppointId());
        if (ObjectUtil.isEmpty(clinicAppoints)) {
            return new SuccessTip(ExceptionHelpEnum.REGIST_QUERY_NULL);
        }
        //只有未报到状态可以取消
        if (clinicAppoints.getAppointStatus().equals("0")) {
            //爽约5次  的 也不能 取消
            List<ClinicAppoints> clinicAppointsList = getClinicAppoints(clinicAppoints.getCusId(), clinicAppoints.getClinicLabel());
            if (CollectionUtils.isNotEmpty(clinicAppointsList) && clinicAppointsList.size() >= 5) {
                return new SuccessTip(ExceptionHelpEnum.REGIST_REFUSE_MORE);
            }
            List<ClinicForRegist> forRegist = getForRegist(DateUtil.formatDate(clinicAppoints.getVisitTime(), "yyyy-MM-dd"), clinicAppoints.getClinicLabel()
                    , clinicAppoints.getTimeDesc(), clinicAppoints.getTimeQuantum());
            if (CollectionUtils.isNotEmpty(forRegist)) {
                ClinicForRegist clinicForRegist = forRegist.get(0);
                if (ObjectUtil.isNotNull(clinicForRegist.getAppointmentNum())) {
                    clinicForRegist.setAppointmentNum(clinicForRegist.getAppointmentNum() - 1);
                    try {
                        Integer update = clinicForRegistMapper.update(clinicForRegist, getlinicForRegistQueryWrapper(DateUtil.formatDate(clinicForRegist.getClinicDate(), "yyyy-MM-dd"), clinicForRegist.getClinicLabel()
                                , clinicForRegist.getTimeDesc(), clinicForRegist.getTimeQuantum()));
                    } catch (Exception e) {
                        throw new ExceptionHelp(ExceptionHelpEnum.REGIST_CLINIC_FOR_REGIST);
                    }
                }
            }
            clinicAppoints.setAppointStatus("3");
            try {
                clinicAppointsMapper.updateById(clinicAppoints);
            } catch (Exception e) {
                throw new ExceptionHelp(ExceptionHelpEnum.REGIST_REFUSE_CANCEL_SE);
            }
            //appointType    05-疫苗预约（不更新clinic_sequen ）
            if (!clinicAppoints.getAppointType().equals("05")) {
                try {
                    ClinicSequen clinicSequen = clinicSequenMapper.selectOne(new QueryWrapper<ClinicSequen>().eq("APPOINT_ID", cancelReq.getAppointId()));
                    clinicSequen.setCancelTime(new Date());
                    clinicSequen.setCanceled("Y");
                    clinicSequenMapper.update(clinicSequen, new QueryWrapper<ClinicSequen>().eq("APPOINT_ID", cancelReq.getAppointId()));
                } catch (Exception e) {
                    ExceptionHelpEnum.REGIST_CLINIC_SEQUEEN.setMessage(ExceptionHelpEnum.REGIST_CLINIC_SEQUEEN.getMessage() + e.getMessage());
                    throw new ExceptionHelp(ExceptionHelpEnum.REGIST_CLINIC_SEQUEEN);
                }
            }

        } else {
            if (clinicAppoints.getAppointStatus().equals("1")) {
                return new SuccessTip(ExceptionHelpEnum.REGIST_QUERY_ARR);
            } else if (clinicAppoints.getAppointStatus().equals("2")) {
                return new SuccessTip(ExceptionHelpEnum.REGIST_QUERY_VISIT);
            } else {
                return new SuccessTip(ExceptionHelpEnum.REGIST_QUERY_CANCEL);
            }
        }
        return tip;
    }

    private List<ClinicForRegist> getForRegist(String visitTime, String clinicLabel, String timeDesc, String timeQuantum) {
        List<ClinicForRegist> clinicForRegists = clinicForRegistMapper.selectList(getlinicForRegistQueryWrapper(visitTime, clinicLabel, timeDesc, timeQuantum));
        return clinicForRegists;
    }

    private List<ClinicAppoints> getClinicAppoints(String patientId, String clinicLabel) {
        List<ClinicAppoints> clinicAppointsList = clinicAppointsMapper.selectList(new QueryWrapper<ClinicAppoints>().apply("appoint_cusid={0} " +
                "and (appoint_status = '0' ) and clinic_label={1} and to_date(to_char(visit_time,'yyyy-mm-dd')||' '||regexp_substr(time_quantum,'^[^-]+'),'yyyy-mm-dd hh24:mi:ss') < sysdate", patientId, clinicLabel));
        return clinicAppointsList;
    }

    private QueryWrapper<ClinicForRegist> getlinicForRegistQueryWrapper(String visitTime, String clinicLabel, String timeDesc, String timeQuantum) {
        QueryWrapper<ClinicForRegist> clinicForRegistQueryWrapper = new QueryWrapper<ClinicForRegist>().apply("CLINIC_DATE = to_date({0},'yyyy-mm-dd hh24:mi:ss') " +
                "and CLINIC_LABEL = {1} and TIME_DESC = {2} and TIME_QUANTUM = {3}", visitTime, clinicLabel, timeDesc, timeQuantum);
        return clinicForRegistQueryWrapper;
    }

}
